package com.bosicloud.cmb.ibp.api.manager.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.models.Model;
import io.swagger.models.Swagger;
import io.swagger.models.properties.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Slf4j
public class PropertyProcessor {

    private final Swagger swagger;

    private int count = 0;

    public PropertyProcessor(Swagger swagger) {
        this.swagger = swagger;
    }

    public JSONObject processProperty(Property property, JSONObject jsonObject, String propertyName, String type) {

        if (property instanceof RefProperty) {
            return processRefProperty((RefProperty) property, jsonObject, propertyName, type);
        } else if (property instanceof ArrayProperty) {
            return processArrayProperty((ArrayProperty) property, jsonObject, propertyName, type);
        } else if (property instanceof MapProperty) {
            return processMapProperty((MapProperty) property, jsonObject, propertyName, type);
        } else if (property instanceof ObjectProperty) {
            return processObjectProperty((ObjectProperty) property, jsonObject, propertyName, type);
        } else {
            return processBaseProperty(property, jsonObject, propertyName, type);
        }
    }

    private JSONObject processRefProperty(RefProperty refProperty, JSONObject resultJsonObject, String key, String type) {
        count++;
        if (StringUtils.isEmpty(key)) {
            key = refProperty.getSimpleRef();
        }
        JSONObject jsonObjectSub = new JSONObject();
        Optional<Model> optionalModel = Optional.ofNullable(swagger.getDefinitions().get(refProperty.getSimpleRef()));
        if (optionalModel.isPresent()) {
            Optional<Map<String, Property>> mapOptional = Optional.ofNullable(optionalModel.get().getProperties());
            if (mapOptional.isPresent()) {
                for (Map.Entry<String, Property> entry : mapOptional.get().entrySet()) {
                    //为了解决循环依赖造成死循环
                    if (count > 2 && Objects.equals(entry.getKey(), key)) {
                        jsonObjectSub = new JSONObject();
                        break;
                    }
                    processProperty(entry.getValue(), jsonObjectSub, entry.getKey(), entry.getValue().getType());
                }
            }
        }

        if (ArrayProperty.TYPE.equalsIgnoreCase(type)) {
            JSONArray jsonArray = new JSONArray();
            jsonArray.add(jsonObjectSub);
            resultJsonObject.put(key, jsonArray);
            return resultJsonObject;
        }
        resultJsonObject.put(key, jsonObjectSub);
        return resultJsonObject;
    }

    private JSONObject processMapProperty(MapProperty mapProperty, JSONObject resultJsonObject, String key, String type) {
        final Property property = mapProperty.getAdditionalProperties();
        if (Objects.nonNull(property)) {
            return processProperty(property, resultJsonObject, key, type);
        }
        return resultJsonObject;
    }

    private JSONObject processArrayProperty(ArrayProperty arrayProperty,
                                            JSONObject resultJsonObject, String key, String type) {
        final Property items = arrayProperty.getItems();
        if (Objects.nonNull(items)) {
            return processProperty(items, resultJsonObject, key, ArrayProperty.TYPE);
        }
        return resultJsonObject;
    }

    private JSONObject processObjectProperty(ObjectProperty objectProperty, JSONObject resultJsonObject, String key, String type) {
        final JSONObject jsonObjectSub = new JSONObject();
        final Map<String, Property> propertyMap = objectProperty.getProperties();
        if (MapUtils.isNotEmpty(propertyMap)) {
            for (Map.Entry<String, Property> entry : propertyMap.entrySet()) {
                processProperty(entry.getValue(), jsonObjectSub, entry.getKey(), type);
            }
        }
        resultJsonObject.put(key, jsonObjectSub);
        return resultJsonObject;
    }

    private JSONObject processBaseProperty(Property property, JSONObject resultJsonObject, String key, String type) {
        if (ArrayProperty.TYPE.equalsIgnoreCase(type)) {
            JSONArray jsonArray = new JSONArray();
            jsonArray.add(property.getType());
            resultJsonObject.put(key, jsonArray);
            return resultJsonObject;
        }
        if (ObjectProperty.TYPE.equalsIgnoreCase(type)) {
            JSONObject jsonObject = new JSONObject();
            resultJsonObject.put(key, jsonObject);
            return resultJsonObject;
        }
        resultJsonObject.put(key, property.getType());
        return resultJsonObject;
    }
}
